home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 451-475 / disk_466 / mosaic / mosaic.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  18KB  |  864 lines

  1. /*
  2.  *  mosaic.c
  3.  *  X version by kirk johnson  october 1990
  4.  *  Amiga version by Loren J. Rittle  Sun Feb 24 06:17:30 1991
  5.  *  Aris, this ones for you...
  6.  *        ...when do I get my pizza :-)
  7.  *
  8.  *  It only took 4-5 hours to port from X, I did it on a dare!
  9.  *  No Copyright N© 1991 Loren J. Rittle.  No rights reserved.
  10.  *  Some code generated via PowerWindows 2.5.
  11.  *  I also used their PD event shell as a starting point.
  12.  *  
  13.  *  Original UseNet post header:
  14.  *  Path: news.larc.nasa.gov!elroy.jpl.nasa.gov!usc!cs.utexas.edu!sun-barr!newstop!exodus!kanchenjunga.LCS.MIT.EDU
  15.  *  From: tuna@kanchenjunga.LCS.MIT.EDU (Kirk 'UhOh' Johnson)
  16.  *  Newsgroups: comp.sources.x
  17.  *  Subject: v11i083: mosaic, Part01/01
  18.  *  Message-ID: <8101@exodus.Eng.Sun.COM>
  19.  *  Date: 17 Feb 91 19:12:47 GMT
  20.  *  Sender: news@exodus.Eng.Sun.COM
  21.  *  Lines: 2409
  22.  *  Approved: argv@sun.com
  23.  *  
  24.  *  Submitted-by: tuna@kanchenjunga.LCS.MIT.EDU (Kirk 'UhOh' Johnson)
  25.  *  Posting-number: Volume 11, Issue 83
  26.  *  Archive-name: mosaic/part01
  27.  *
  28.  *  Thanks to Kirk for releasing such a nice simple game program with source...
  29.  *  Hard Drive Installable and Multitasks, thus better than any psygnosis game...
  30.  */
  31.  
  32. #include <exec/types.h>
  33. #include <exec/io.h>
  34. #include <exec/memory.h>
  35. #include <libraries/dos.h>
  36. #include <intuition/intuition.h>
  37. #include <graphics/gfxmacros.h>
  38. #include <proto/all.h>
  39. #include <stdlib.h>
  40. #include <time.h>
  41. #include <math.h>
  42. #include <string.h>
  43. #include "mosaic.h"
  44.  
  45. struct IntuitionBase *IntuitionBase = NULL;
  46. struct GfxBase *GfxBase = NULL;
  47.  
  48. SHORT BorderVectors1[] =
  49. {
  50.   0, 0,
  51.   65, 0,
  52.   65, 25,
  53.   0, 25,
  54.   0, 0
  55. };
  56.  
  57. struct Border Border1 =
  58. {
  59.   -1, -1,
  60.   3, 0, JAM1,
  61.   5,
  62.   BorderVectors1,
  63.   NULL
  64. };
  65.  
  66. struct IntuiText IText1 =
  67. {
  68.   3, 0, JAM2,
  69.   5, 7,
  70.   NULL,
  71.   "Restart",
  72.   NULL
  73. };
  74.  
  75. struct Gadget Gadget1 =
  76. {
  77.   NULL,
  78.   366, 107,
  79.   64, 24,
  80.   NULL,
  81.   RELVERIFY,
  82.   BOOLGADGET,
  83.   (APTR) & Border1,
  84.   NULL,
  85.   &IText1,
  86.   NULL,
  87.   NULL,
  88.   NULL,
  89.   NULL
  90. };
  91.  
  92. struct IntuiText IText2 =
  93. {
  94.   3, 0, JAM2,
  95.   366, 138,
  96.   NULL,
  97.   "Next:",
  98.   NULL
  99. };
  100.  
  101. struct NewWindow NewWindowStructure1 =
  102. {
  103.   20, 10,
  104.   440, 188,
  105.   0, 1,
  106.   MOUSEBUTTONS + MOUSEMOVE + GADGETUP + CLOSEWINDOW + RAWKEY,
  107.   WINDOWDRAG + WINDOWDEPTH + REPORTMOUSE + WINDOWCLOSE + ACTIVATE + NOCAREREFRESH,
  108.   &Gadget1,
  109.   NULL,
  110.   "Mosaic, Amiga Version by Loren J. Rittle\0Sun Feb 24 04:36:18 1991",
  111.   NULL,
  112.   NULL,
  113.   450, 188,
  114.   450, 188,
  115.   WBENCHSCREEN
  116. };
  117.  
  118. struct NewWindow NewWindowStructure2 =
  119. {
  120.   465, 10,
  121.   170, 120,
  122.   0, 1,
  123.   NULL,
  124.   WINDOWDRAG + WINDOWDEPTH + NOCAREREFRESH,
  125.   NULL,
  126.   NULL,
  127.   "Mosaic Score",
  128.   NULL,
  129.   NULL,
  130.   450, 188,
  131.   450, 188,
  132.   WBENCHSCREEN
  133. };
  134.  
  135. char *ScoreFile = "mosaic.scores";
  136.  
  137. Word tile[NTiles];        /* the board */
  138. Word piece[NPieces];        /* the "deck" of pieces */
  139. Word nextpiece;            /* index into the deck */
  140.  
  141. Word size[NTiles];        /* score data structures */
  142. Word parent[NTiles];
  143.  
  144. Word tscore[3];            /* total score */
  145. Word pscore[3];            /* last piece score */
  146. Word remain[3];            /* tiles remaining */
  147.  
  148. static char buf[256];
  149.  
  150. NameAndScore highscore[NHighScores];
  151.  
  152. int highlitX = 0;
  153. int highlitY = 0;
  154.  
  155. int highlitXonDown;
  156. int highlitYonDown;
  157.  
  158. BPTR SpeakFH = NULL;
  159.  
  160. struct Window *wG = NULL;
  161. struct RastPort *rpG;
  162.  
  163. struct Window *wS = NULL;
  164. struct RastPort *rpS;
  165.  
  166. #define BoundVarVal(var, min, max) \
  167. {                                  \
  168.   if ((var) < (min))               \
  169.     (var) = (min);                 \
  170.   else if ((var) > (max))          \
  171.     (var) = (max);                 \
  172. }
  173.  
  174. UWORD chip backfill[8] =
  175. {0x1111, 0x4444, 0x1111, 0x4444, 0x1111, 0x4444, 0x1111, 0x4444};
  176.  
  177. UWORD chip solid[8] =
  178. {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF};
  179.  
  180. void
  181. main (void)
  182. {
  183.   UWORD code;
  184.   ULONG class;
  185.   APTR object;
  186.   int MouseX, MouseY;
  187.   int x, y;
  188.  
  189.   struct IntuiMessage *message;
  190.  
  191.   IntuitionBase = OpenLibrary ("intuition.library", 0);
  192.   GfxBase = OpenLibrary ("graphics.library", 0);
  193.   if (!IntuitionBase || !GfxBase)
  194.     fatal ("Can't open Intuition and/or Graphics Library.");
  195.  
  196.   wG = OpenWindow (&NewWindowStructure1);
  197.   if (wG == NULL)
  198.     fatal ("Can't open a window.");
  199.   rpG = wG->RPort;
  200.  
  201.   wS = OpenWindow (&NewWindowStructure2);
  202.   if (wS == NULL)
  203.     fatal ("Can't open a window.");
  204.   rpS = wS->RPort;
  205.  
  206.   {
  207.     struct Process* proc = (struct Process *)FindTask(0L);
  208.     APTR temp = proc->pr_WindowPtr;
  209.  
  210.     proc->pr_WindowPtr = (APTR)-1L;
  211.     SpeakFH = Open ("speak:", MODE_NEWFILE);
  212.     proc->pr_WindowPtr = temp;
  213.   }
  214.  
  215.  
  216.   PrintIText (rpG, &IText2, 0, 0);
  217.  
  218.   ReadHighScores ();
  219.  
  220. restart:
  221.   InitGame ();
  222.   drawScore ();
  223.   SetAPen (rpG, 2);
  224.   SetAfPt (rpG, (void *) backfill, 3);
  225.   RectFill (rpG, 20, 14, 24 * 14 + 20, 24 * 7 + 14);
  226.  
  227.   SetAPen (rpG, 3);
  228.   for (x = 0; x < 25; x++)
  229.     {
  230.       Move (rpG, x * 14 + 20, 14);
  231.       Draw (rpG, x * 14 + 20, 24 * 7 + 14);
  232.     }
  233.  
  234.   for (y = 0; y < 25; y++)
  235.     {
  236.       Move (rpG, 20, y * 7 + 14);
  237.       Draw (rpG, 24 * 14 + 20, y * 7 + 14);
  238.     }
  239.  
  240.   while (1)
  241.     {
  242.       WaitPort (wG->UserPort);
  243.       while ((message = (struct IntuiMessage *) GetMsg (wG->UserPort)) != NULL)
  244.     {
  245.       code = message->Code;
  246.       object = message->IAddress;
  247.       class = message->Class;
  248.       MouseX = message->MouseX;
  249.       MouseY = message->MouseY;
  250.       ReplyMsg ((struct Message *) message);
  251.       if (class == CLOSEWINDOW)
  252.         QuitGame (0);
  253.       /*
  254.            * This is very kludgy, don't follow this example of how to read
  255.            * keys... This is a quick hack to allow the 'a' for auto play
  256.            * feature to work.  Try it, you may hate it! Because, the
  257.            * AutoPlay() function is not too smart.  LJR
  258.            */
  259.       if ((class == RAWKEY) && (code == 32))
  260.         AutoPlay ();
  261.       /* Here again, quick hack to support open/closing of
  262.        * score window via 's'.  LJR
  263.        */
  264.       if ((class == RAWKEY) && (code == 33))
  265.         {
  266.           if (wS == NULL)
  267.         {
  268.               wS = OpenWindow (&NewWindowStructure2);
  269.               if (wS == NULL)
  270.             fatal ("Can't open a window.");
  271.               rpS = wS->RPort;
  272.           drawScore ();
  273.         }
  274.           else
  275.         {
  276.           CloseWindow(wS);
  277.           wS = NULL;
  278.         }
  279.         }
  280.       if (class == MOUSEMOVE)
  281.         MoveBox (MouseX, MouseY);
  282.       if (class == MOUSEBUTTONS)
  283.         if (code & 0x0080)
  284.           {
  285.         if ((highlitXonDown == highlitX) &&
  286.             (highlitYonDown == highlitY))
  287.           {
  288.             if ((nextpiece < NPieces) &&
  289.             (DropPiece (highlitY, highlitX, piece[nextpiece])))
  290.               {
  291.             nextpiece += 1;
  292.             drawNext ();
  293.  
  294.             if (nextpiece == NPieces)
  295.               {
  296.                 MoveBox (-1, -1);
  297.                 CheckHighScore ();
  298.               }
  299.               }
  300.             else
  301.               if (SpeakFH)
  302.             Write (SpeakFH, "No Way!", 7);
  303.               else
  304.             DisplayBeep (NULL);
  305.           }
  306.         else
  307.           if (SpeakFH)
  308.             Write (SpeakFH, "Un-do!", 7);
  309.           else
  310.             DisplayBeep (NULL);
  311.           }
  312.         else
  313.           {
  314.         highlitXonDown = highlitX;
  315.         highlitYonDown = highlitY;
  316.           }
  317.       if ((class == GADGETUP) || (class == GADGETDOWN))
  318.         if (object == (void *) &Gadget1)
  319.           goto restart;
  320.     }
  321.     }
  322.  
  323. }
  324.  
  325. void
  326. MoveBox (int MouseX, int MouseY)
  327. {
  328.   int x, y;
  329.   int newX = (MouseX - 27) / 14;
  330.   int newY = (MouseY - 17) / 7;
  331.  
  332.   BoundVarVal (newX, 0, 22);
  333.   BoundVarVal (newY, 0, 22);
  334.  
  335.   if ((newX == highlitX) && (newY == highlitY))
  336.     return;
  337.  
  338.   SetAPen (rpG, 3);
  339.   for (x = highlitX; x < highlitX + 3; x++)
  340.     {
  341.       Move (rpG, x * 14 + 20, highlitY * 7 + 14);
  342.       Draw (rpG, x * 14 + 20, highlitY * 7 + 14 + 14);
  343.     }
  344.  
  345.   for (y = highlitY; y < highlitY + 3; y++)
  346.     {
  347.       Move (rpG, highlitX * 14 + 20, y * 7 + 14);
  348.       Draw (rpG, highlitX * 14 + 20 + 28, y * 7 + 14);
  349.     }
  350.  
  351.   SetAfPt (rpG, (void *) backfill, 3);
  352.   SetAPen (rpG, 2);
  353.   if (!tile[highlitY * BoardSize + highlitX])
  354.     RectFill (rpG, highlitX * 14 + 21, highlitY * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+1) * 7 + 13);
  355.   if (!tile[highlitY * BoardSize + highlitX + 1])
  356.     RectFill (rpG, (highlitX+1) * 14 + 21, highlitY * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+1) * 7 + 13);
  357.   if (!tile[(highlitY + 1) * BoardSize + highlitX])
  358.     RectFill (rpG, highlitX * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+2) * 7 + 13);
  359.   if (!tile[(highlitY + 1) * BoardSize + highlitX + 1])
  360.     RectFill (rpG, (highlitX+1) * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+2) * 7 + 13);
  361.  
  362.   if (nextpiece == NPieces)
  363.     {
  364.       highlitX = highlitY = 0;
  365.       return;
  366.     }
  367.   highlitX = newX;
  368.   highlitY = newY;
  369.  
  370.   SetAPen (rpG, 1);
  371.   for (x = highlitX; x < highlitX + 3; x++)
  372.     {
  373.       Move (rpG, x * 14 + 20, highlitY * 7 + 14);
  374.       Draw (rpG, x * 14 + 20, highlitY * 7 + 14 + 14);
  375.     }
  376.  
  377.   for (y = highlitY; y < highlitY + 3; y++)
  378.     {
  379.       Move (rpG, highlitX * 14 + 20, y * 7 + 14);
  380.       Draw (rpG, highlitX * 14 + 20 + 28, y * 7 + 14);
  381.     }
  382.  
  383.   SetAfPt (rpG, (void *) solid, 3);
  384.   if (!tile[highlitY * BoardSize + highlitX])
  385.     {
  386.       SetAPen (rpG, piece[nextpiece] & 0x0003);
  387.       RectFill (rpG, highlitX * 14 + 21, highlitY * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+1) * 7 + 13);
  388.     }
  389.   if (!tile[highlitY * BoardSize + highlitX + 1])
  390.     {
  391.       SetAPen (rpG, (piece[nextpiece] & 0x000C)>>2);
  392.       RectFill (rpG, (highlitX+1) * 14 + 21, highlitY * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+1) * 7 + 13);
  393.     }
  394.   if (!tile[(highlitY + 1) * BoardSize + highlitX])
  395.     {
  396.       SetAPen (rpG, (piece[nextpiece] & 0x0030)>>4);
  397.       RectFill (rpG, highlitX * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+1) * 14 + 19, (highlitY+2) * 7 + 13);
  398.     }
  399.   if (!tile[(highlitY + 1) * BoardSize + highlitX + 1])
  400.     {
  401.       SetAPen (rpG, (piece[nextpiece] & 0x00C0)>>6);
  402.       RectFill (rpG, (highlitX+1) * 14 + 21, (highlitY+1) * 7 + 15, (highlitX+2) * 14 + 19, (highlitY+2) * 7 + 13);
  403.     }
  404. }
  405.  
  406. void
  407. QuitGame (int rc)
  408. {
  409.   if (wG)
  410.     CloseWindow (wG);
  411.   if (wS)
  412.     CloseWindow (wS);
  413.   if (SpeakFH)
  414.     Close (SpeakFH);
  415.   if (GfxBase != NULL)
  416.     CloseLibrary (GfxBase);
  417.   if (IntuitionBase != NULL)
  418.     CloseLibrary (IntuitionBase);
  419.   exit (0);
  420. }
  421.  
  422. void
  423. warning (char *msg)
  424. {
  425.   fflush (stdout);
  426.   fprintf (stderr, "%s: warning! %s\n", AppName, msg);
  427.   fflush (stderr);
  428. }
  429.  
  430. void
  431. fatal (char *msg)
  432. {
  433.   fflush (stdout);
  434.   fprintf (stderr, "%s: %s\n", AppName, msg);
  435.   QuitGame (1);
  436. }
  437.  
  438. void
  439. ReadHighScores (void)
  440. {
  441.   int i;
  442.   FILE *s;
  443.  
  444.   s = fopen (ScoreFile, "r");
  445.   if (s == NULL)
  446.     {
  447.       warning ("unable to open score file; creating new one");
  448.  
  449.       for (i = 0; i < NHighScores; i++)
  450.     {
  451.       strcpy (highscore[i].uname, ".");
  452.       highscore[i].score = -1;
  453.     }
  454.  
  455.       WriteHighScores ();
  456.     }
  457.   else
  458.     {
  459.       for (i = 0; i < NHighScores; i++)
  460.     {
  461.       fgets (buf, 30, s);
  462.       if (sscanf (buf, "%s %d",
  463.               highscore[i].uname, &highscore[i].score) != 2)
  464.         fatal ("incomplete score file read");
  465.     }
  466.       fclose (s);
  467.     }
  468. }
  469.  
  470.  
  471. void
  472. WriteHighScores (void)
  473. {
  474.   int i;
  475.   FILE *s;
  476.  
  477.   s = fopen (ScoreFile, "w");
  478.   if (s == NULL)
  479.     fatal ("unable to open score file");
  480.  
  481.   for (i = 0; i < NHighScores; i++)
  482.     fprintf (s, "%s %d\n", highscore[i].uname, highscore[i].score);
  483.  
  484.   fclose (s);
  485. }
  486.  
  487. void
  488. CheckHighScore (void)
  489. {
  490.   int i;
  491.   int score;
  492.   char *uname;
  493.  
  494.   uname = getenv ("USERNAME");
  495.   if (uname == NULL)
  496.     uname = "Unknown_Puzzle_Solver";
  497.   score = tscore[0] + tscore[1] + tscore[2];
  498.  
  499.   /*
  500.    * note that we don't actually try to do any locking of the high score
  501.    * file during this critical section ...
  502.    */
  503.  
  504.   ReadHighScores ();
  505.  
  506.   for (i = 0; i < NHighScores; i++)
  507.     if (strcmp (highscore[i].uname, uname) == 0)
  508.       break;
  509.  
  510.   if (i == NHighScores)
  511.     i = NHighScores - 1;
  512.  
  513.   if (score > highscore[i].score)
  514.     {
  515.       while ((i > 0) && (score > highscore[i - 1].score))
  516.     {
  517.       strcpy (highscore[i].uname, highscore[i - 1].uname);
  518.       highscore[i].score = highscore[i - 1].score;
  519.       i -= 1;
  520.     }
  521.       strcpy (highscore[i].uname, uname);
  522.       highscore[i].score = score;
  523.  
  524.       WriteHighScores ();
  525.  
  526.       if (SpeakFH)
  527.     {
  528.       Write (SpeakFH, "Congratulations!", 16);
  529.       Write (SpeakFH, "You got a hi score.", 19);
  530.     }
  531.       else
  532.     DisplayBeep (NULL);
  533.     }
  534.   drawHighScores ();
  535. }
  536.  
  537. void
  538. AutoPlay (void)
  539. {
  540.   int r, c;
  541.  
  542.   while (nextpiece < NPieces)
  543.     {
  544.       do
  545.     {
  546.       r = rand () % (BoardSize - 1);
  547.       c = rand () % (BoardSize - 1);
  548.     }
  549.       while (!DropPiece (r, c, piece[nextpiece]));
  550.  
  551.       nextpiece += 1;
  552.       drawNext ();
  553.  
  554.       if (nextpiece == NPieces)
  555.     {
  556.       MoveBox (-1, -1);
  557.       CheckHighScore ();
  558.     }
  559.     }
  560. }
  561.  
  562. void
  563. UpdateAndScore (int r, int c, Word score[])
  564. {
  565.   int i;
  566.  
  567.   i = r * BoardSize + c;
  568.  
  569.   PossiblyMerge (i, i + 1);
  570.   PossiblyMerge (i + BoardSize, i + BoardSize + 1);
  571.  
  572.   PossiblyMerge (i, i + BoardSize);
  573.   PossiblyMerge (i + 1, i + BoardSize + 1);
  574.  
  575.   if (c >= 1)
  576.     {
  577.       PossiblyMerge (i, i - 1);
  578.       PossiblyMerge (i + BoardSize, i + BoardSize - 1);
  579.     }
  580.   if (r >= 1)
  581.     {
  582.       PossiblyMerge (i, i - BoardSize);
  583.       PossiblyMerge (i + 1, i - BoardSize + 1);
  584.     }
  585.   if (c <= (BoardSize - 3))
  586.     {
  587.       PossiblyMerge (i + 1, i + 2);
  588.       PossiblyMerge (i + BoardSize + 1, i + BoardSize + 2);
  589.     }
  590.   if (r <= (BoardSize - 3))
  591.     {
  592.       PossiblyMerge (i + BoardSize, i + (2 * BoardSize));
  593.       PossiblyMerge (i + BoardSize + 1, i + (2 * BoardSize) + 1);
  594.     }
  595.   /* compute the new score */
  596.   for (i = 0; i < 3; i++)
  597.     score[i] = 0;
  598.   for (i = 0; i < NTiles; i++)
  599.     if ((tile[i] != 0) && (parent[i] == i))
  600.       score[tile[i] - 1] += size[i] * size[i];
  601. }
  602.  
  603. void
  604. PossiblyMerge (int i, int j)
  605. {
  606.   Word irep;
  607.   Word jrep;
  608.   Word scan;
  609.  
  610.   /* tiles are not the same color */
  611.   if (tile[i] != tile[j])
  612.     return;
  613.  
  614.   /* find i's rep */
  615.   irep = i;
  616.   while (parent[irep] != irep)
  617.     irep = parent[irep];
  618.  
  619.   /* compress path from i to irep */
  620.   scan = i;
  621.   while (parent[scan] != scan)
  622.     {
  623.       scan = parent[scan];
  624.       parent[scan] = irep;
  625.     }
  626.  
  627.   /* find j's rep */
  628.   jrep = j;
  629.   while (parent[jrep] != jrep)
  630.     jrep = parent[jrep];
  631.  
  632.   /* compress path from j to jrep */
  633.   scan = j;
  634.   while (parent[scan] != scan)
  635.     {
  636.       scan = parent[scan];
  637.       parent[scan] = jrep;
  638.     }
  639.  
  640.   /* tiles are already in the same set */
  641.   if (irep == jrep)
  642.     return;
  643.  
  644.   /* merge the sets */
  645.   if (size[irep] > size[jrep])
  646.     {
  647.       parent[jrep] = irep;
  648.       size[irep] += size[jrep];
  649.     }
  650.   else
  651.     {
  652.       parent[irep] = jrep;
  653.       size[jrep] += size[irep];
  654.     }
  655. }
  656.  
  657. int
  658. DropPiece (int r, int c, Word p)
  659. {
  660.   int idx;
  661.   Word type;
  662.   Word nscore[3];
  663.  
  664.   idx = r * BoardSize + c;
  665.  
  666.   /* check for illegal move */
  667.   if ((tile[idx] != 0) ||
  668.       (tile[idx + 1] != 0) ||
  669.       (tile[idx + BoardSize] != 0) ||
  670.       (tile[idx + BoardSize + 1] != 0))
  671.     return 0;
  672.  
  673.   /* place the piece */
  674.   type = p & 0x03;
  675.   tile[idx] = type;
  676.   remain[type - 1] -= 1;
  677.   p >>= 2;
  678.  
  679.   type = p & 0x03;
  680.   tile[idx + 1] = type;
  681.   remain[type - 1] -= 1;
  682.   p >>= 2;
  683.  
  684.   type = p & 0x03;
  685.   tile[idx + BoardSize] = type;
  686.   remain[type - 1] -= 1;
  687.   p >>= 2;
  688.  
  689.   type = p & 0x03;
  690.   tile[idx + BoardSize + 1] = p & 0x03;
  691.   remain[type - 1] -= 1;
  692.  
  693.   /* update the score */
  694.   UpdateAndScore (r, c, nscore);
  695.   for (idx = 0; idx < 3; idx++)
  696.     {
  697.       pscore[idx] = nscore[idx] - tscore[idx];
  698.       tscore[idx] = nscore[idx];
  699.     }
  700.  
  701.   /* redraw */
  702.   drawTile (r++, c);
  703.   drawTile (r, c++);
  704.   drawTile (r--, c);
  705.   drawTile (r, c);
  706.   drawScore ();
  707.  
  708.   return 1;
  709. }
  710.  
  711. void
  712. InitGame (void)
  713. {
  714.   int i, j, k, l;
  715.   int idx, swap;
  716.  
  717.   /* randomize */
  718.   srand ((int) time (NULL));
  719.  
  720.   /* clear the board */
  721.   for (i = 0; i < NTiles; i++)
  722.     tile[i] = 0;
  723.  
  724.   /* set up deck */
  725.   idx = 0;
  726.   for (i = 1; i <= 3; i++)
  727.     for (j = 1; j <= 3; j++)
  728.       for (k = 1; k <= 3; k++)
  729.     for (l = 1; l <= 3; l++)
  730.       piece[idx++] = (i << 6) | (j << 4) | (k << 2) | (l << 0);
  731.  
  732.   /* shuffle */
  733.   for (i = 0; i < 1000; i++)
  734.     {
  735.       idx = rand () % NPieces;
  736.       swap = piece[idx];
  737.       piece[idx] = piece[0];
  738.       piece[0] = swap;
  739.     }
  740.   nextpiece = 0;
  741.  
  742.   /* clear score data structures */
  743.   for (i = 0; i < NTiles; i++)
  744.     {
  745.       size[i] = 1;
  746.       parent[i] = i;
  747.     }
  748.  
  749.   for (i = 0; i < 3; i++)
  750.     {
  751.       tscore[i] = 0;
  752.       pscore[i] = 0;
  753.       remain[i] = (NPieces * 4) / 3;
  754.     }
  755.   drawNext ();
  756. }
  757.  
  758. void
  759. drawTile (int r, int c)
  760. {
  761.   int x, y;
  762.  
  763.   x = c * 14 + 20;
  764.   y = r * 7 + 14;
  765.  
  766.   SetAfPt (rpG, (void *) solid, 3);
  767.   SetAPen (rpG, tile[r * BoardSize + c]);
  768.   RectFill (rpG, x + 1, y + 1, x + 13, y + 6);
  769. }
  770.  
  771. void
  772. drawHighScores (void)
  773. {
  774.   int i;
  775.  
  776.   SetAPen (rpG, 1);
  777.   for (i = 0; i < NHighScores; i++)
  778.     if (highscore[i].score > 0)
  779.       {
  780.     sprintf (buf, "%-24s %5d", highscore[i].uname, highscore[i].score);
  781.     Move (rpG, 50, 30 + i * 14);
  782.     Text (rpG, buf, strlen (buf));
  783.       }
  784. }
  785.  
  786. void
  787. drawNext (void)
  788. {
  789.   int p = (nextpiece < NPieces) ? piece[nextpiece] : 0;
  790.   int x = 26 * 14 + 20;
  791.   int y = 20 * 7 + 14;
  792.  
  793.   SetAfPt (rpG, (void *) solid, 3);
  794.   SetAPen (rpG, p & 0x03);
  795.   RectFill (rpG, x + 1, y + 1, x + 13, y + 6);
  796.   p >>= 2;
  797.   SetAPen (rpG, p & 0x03);
  798.   RectFill (rpG, x + 15, y + 1, x + 27, y + 6);
  799.   p >>= 2;
  800.   SetAPen (rpG, p & 0x03);
  801.   RectFill (rpG, x + 1, y + 8, x + 13, y + 13);
  802.   p >>= 2;
  803.   SetAPen (rpG, p & 0x03);
  804.   RectFill (rpG, x + 15, y + 8, x + 27, y + 13);
  805. }
  806.  
  807. void
  808. drawScore (void)
  809. {
  810.   int i, total;
  811.  
  812.   if (!wS)
  813.     return;
  814.  
  815.   SetAPen(rpS, 3);
  816.   Move (rpS, 10, 20);
  817.   Text (rpS, "to play:", 8);
  818.  
  819.   Move (rpS, 10, 30);
  820.   for (i = 0; i < 3; i++)
  821.     {
  822.       SetAPen(rpS, i+1);
  823.       sprintf (buf, "%5d ", remain[i]);
  824.       Text (rpS, buf, strlen (buf));
  825.     }
  826.  
  827.   SetAPen(rpS, 3);
  828.   Move (rpS, 10, 50);
  829.   Text (rpS, "total:", 6);
  830.  
  831.   total = 0;
  832.   Move (rpS, 10, 60);
  833.   for (i = 0; i < 3; i++)
  834.     {
  835.       SetAPen(rpS, i+1);
  836.       total += tscore[i];
  837.       sprintf (buf, "%5d ", tscore[i]);
  838.       Text (rpS, buf, strlen (buf));
  839.     }
  840.  
  841.   SetAPen(rpS, 3);
  842.   sprintf (buf, "%5d", total);
  843.   Move (rpS, 10, 70);
  844.   Text (rpS, buf, strlen (buf));
  845.  
  846.   Move (rpS, 10, 90);
  847.   Text (rpS, "piece:", 6);
  848.  
  849.   total = 0;
  850.   Move (rpS, 10, 100);
  851.   for (i = 0; i < 3; i++)
  852.     {
  853.       SetAPen(rpS, i+1);
  854.       total += pscore[i];
  855.       sprintf (buf, "%5d ", pscore[i]);
  856.       Text (rpS, buf, strlen (buf));
  857.     }
  858.  
  859.   SetAPen(rpS, 3);
  860.   sprintf (buf, "%5d", total);
  861.   Move (rpS, 10, 110);
  862.   Text (rpS, buf, strlen (buf));
  863. }
  864.